<template>
  <div>
    <q-banner inline-actions class="text-black bg-listcolor">
        {{ tableCaption }}
        <template v-slot:action>
          <q-btn
            dense
            flat
            unelevated
            round
            color="primary"
            @click="expand = !expand" :icon="expand ? 'expand_less' : 'expand_more'"
          />
        </template>
    </q-banner>
    <q-table v-show="expand"
      :data="qTableData"
      :columns="qTableColums"
      :row-key="getRecId"
      selection="multiple"
      :selected.sync="selected"
      :pagination.sync="tablePagination"
      :loading="loading"
      separator="cell"
      hide-bottom
      flat>
      <template v-slot:top>
        <q-btn
          :disable="selected.length == 0"
           dense flat unelevated round
          @click="onDeleteClickAction()"
          color="negative"
          icon="delete_forever"
        />
        <q-btn
          dense flat unelevated round
          @click="onNewClickAction()"
          color="primary"
          icon="add"
        />
      </template>

      <template v-slot:body="props">

        <q-tr :props="props">
          <q-td>
            <q-checkbox v-model="props.selected" />
          </q-td>
          <q-td key="dataClickAction" :props="props">
            <q-btn unelevated
              @click="onDeleteClickAction(props.row)"
              color="negative"
              icon="delete_forever"
              flat
              round
              dense
            ></q-btn>
            <q-btn
            v-if="(oneToOneMainToSubTables.length + oneToManySubTables.length) > 0"
            color="primary"
            dense flat unelevated round
            @click="props.expand = !props.expand"
            :icon="props.expand ? 'expand_less' : 'expand_more'"/>
          </q-td>
          <q-td :key="index" v-for="(value, colKey, index) in filterRow(props.row)">
              <div class="row items-baseline content-center"
                style="border-bottom: 1px solid rgba(0,0,0,0.12)" 
               v-if="isHasRelationTableNameByKey(colKey, props.cols)">
                <div class="col-10">
                  <span >{{ props.row[colKey] | relationDataFormat(colKey, props.cols) }}</span>
                </div>
                <div class="col-2">
                  <q-btn round dense  flat icon="zoom_in" @click="openDialogClickAction(props, colKey)" />
                </div>
              </div>

              <q-input v-else-if="isDateTimeTypeByKey(colKey, props.cols)"
                  v-model="props.row[colKey]">
                <template v-slot:prepend>
                  <q-icon name="event" class="cursor-pointer">
                    <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
                      <q-date v-model="props.row[colKey]"
                      mask="YYYY-MM-DD HH:mm:ss"
                      @input="hideRefPopProxyAction('qDateProxy')" />
                    </q-popup-proxy>
                  </q-icon>
                </template>

                <template v-slot:append>
                  <q-icon name="access_time" class="cursor-pointer">
                    <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
                      <q-time v-model="props.row[colKey]" mask="YYYY-MM-DD HH:mm:ss"
                      format24h with-seconds
                      @input="hideRefPopProxyAction('qTimeProxy')" />
                    </q-popup-proxy>
                  </q-icon>
                </template>
              </q-input>

              <q-input v-else-if="isDateTypeByKey(colKey, props.cols)"
                v-model="props.row[colKey]">
                <template v-slot:append>
                  <q-icon name="event" class="cursor-pointer">
                    <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
                      <q-date v-model="props.row[colKey]"
                      mask="YYYY-MM-DD"
                      @input="hideRefPopProxyAction('qDateProxy')" />
                    </q-popup-proxy>
                  </q-icon>
                </template>
              </q-input>

              <q-input v-else-if="isTimeTypeByKey(colKey, props.cols)"
                v-model="props.row[colKey]">
                <template v-slot:append>
                  <q-icon name="access_time" class="cursor-pointer">
                    <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
                      <q-time v-model="props.row[colKey]" mask="HH:mm:ss"
                      format24h with-seconds
                      @input="hideRefPopProxyAction('qTimeProxy')" />
                    </q-popup-proxy>
                  </q-icon>
                </template>
              </q-input>

              <q-input
                v-else-if="isNumberTypeByKey(colKey, props.cols)"
                v-model="props.row[colKey]"
                style="min-width: 80px;"
                type="number" >
              </q-input>

              <CFile v-else-if="isAttachmentTypeByKey(colKey, props.cols)"
                 v-model="props.row[colKey]"
                 @input="(data)=>{
                  props.row[colKey] = data.url;
                 }">
              </CFile>

              <q-toggle v-else-if="isBoolTypeByKey(colKey, props.cols)"
                v-model="props.row[colKey]">
              </q-toggle>

              <q-input
                v-else style="min-width: 80px;"
                :placeholder="getPlaceHolderByKey(colKey, props.cols)"
                v-model="props.row[colKey]"
                :type="getInputTextType(props, colKey)" >
                <template v-slot:append
                  v-if="isPasswordTextType(props, colKey)" >
                  <q-icon
                    :name="getInputIcon(props, colKey)"
                    class="cursor-pointer"
                    @click="togglePwd(colKey, props.key)"
                  />
                </template>
              </q-input>
          </q-td>
        </q-tr>

        <q-tr v-if="(oneToOneMainToSubTables.length + oneToManySubTables.length) > 0"
          v-show="props.expand" :props="props">
          <q-td colspan="100%">
            <div class="text-left">
              <div :key="item.relationName" v-for="item in oneToOneMainToSubTables">
                <CTableNew
                :fkColumnName="item.fkColumnName"
                :ref="getRefName('rTableNewRef', item.relationName, props.row)"
                :dataSource="dataSource"
                :tableName="item.tableName" ></CTableNew>
              </div>

              <div :key="item.relationName" v-for="item in oneToManySubTables">
                <CTableList
                :fkColumnName="item.fkColumnName"
                :ref="getRefName('rTableListRef', item.relationName, props.row)"
                :dataSource="dataSource"
                :tableName="item.tableName"
                 ></CTableList>
              </div>
            </div>
          </q-td>
        </q-tr>
      </template>
    </q-table>
    <q-separator v-if="qTableData.length > 0" />
  </div>
</template>

<style lang="stylus">
.required:before
  content: "* ";
  color: red;
</style>

<script>
import { tableService } from "../../service";
import { metadataTableService } from "../../service";
import { metadataRelationService } from "../../service";
import { extend } from 'quasar'
import CTableListReadDialog from '../../components/CTableListRead/CTableListReadDialog'

export default {
  name: "CTableList",
  props: {
    dataSource: {
      required: true
    },
    tableName: {
      required: true
    },
    fkColumnName: {
      required: false,
      type: String,
      default: "",
    }
  },

  data() {
    return {
      passwordMap: {},
      passwordMaps: {},
      relationMetadataMap: {},
      tableCaption: "",
      primaryNames: [],
      expand: true,
      insertColumns: [],
      relationMap: {},
      oneToOneMainToSubTables: [],
      oneToManySubTables: [],

      qTableData: [],
      selected: [],
      loading: true,
      pagination: {
        page: 1,
        rowsPerPage: 10,
        count: 0
      },
      tablePagination: {
        rowsPerPage: 10
      },
      visibleColumns: [
      ],
      qTableColums: [
      ]
    };
  },

  created() {
    console.info("CTableNew created");
    this.init();
  },
  mounted: function() {
    console.info("CTableNew mounted");
  },
  activated: function() {
    console.info("CTableNew->activated");
  },
  deactivated: function() {
    console.info("CTableNew->deactivated");
  },
  updated: function() {
    console.info("CTableNew->updated");
  },
  destroyed: function() {
    console.info("CTableNew->destroyed");
  },
  filters: {
    relationDataFormat: function(value, colKey, cols) {
       const col = cols.find(t => t.name === colKey);
       const dicFormat = function(v) {
          let data = null;

          if (v) {
           if (col.relationDisplayColumns.length > 0) {
              let displayValues = [];
              col.relationDisplayColumns.forEach((t) => {
                  v[t.name] && displayValues.push(v[t.name]);
              });


              if (displayValues.length > 0) {
                data = displayValues.join("|");
              } else {
                data = v[col.relationColumnName];
              }
           } else {
              data = v[col.relationColumnName];
           }
          }

          return data;
        }

        let ret = value;
        if (col && value) {
          if (Array.isArray(value)) {
             let values = [];
             value.forEach((t) => {
                const subV = dicFormat(t);
                if (subV) {
                  values.push(subV);
                }
             });

             ret = values.join(",");
          } else {
            ret = dicFormat(value);
          }
        }
        return (ret != null && ret != undefined) ? ret : value;
    }
  },
  computed: {
  },
  methods: {
    async init(tableName) {
      this.insertColumns = [];

      await this.loadMeta();
    },

    filterRow(row) {
      let newRow = {};
      for (let key in row) {
        if (key != 'id') {
          newRow[key] = row[key];
        }
      }

      return newRow;
    },

    isHasRelationTableNameByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find.relationTableName) {
        return true;
      }
      return false;
    },

    isDateTimeTypeByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find) {
        if (find.dataType === "DATETIME") {
          return true
        }
      }
      return false;
    },

    isDateTypeByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find) {
        if (find.dataType === "DATE") {
          return true
        }
      }
      return false;
    },

    isTimeTypeByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find) {
        if (find.dataType === "TIME") {
          return true
        }
      }
      return false;
    },

    isNumberTypeByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find) {
        if (find.dataType === "TINYINT"
          || find.dataType === "SMALLINT"
          || find.dataType === "MEDIUMINT"
          || find.dataType === "INT"
          || find.dataType === "BIGINT") {
          return true
        }
      }
      return false;
    },

    isBoolTypeByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find) {
        if (find.dataType === "BOOL") {
          return true
        }
      }
      return false;
    },

    isAttachmentTypeByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find) {
        if (find.dataType === "ATTACHMENT") {
          return true
        }
      }
      return false;
    },

    togglePwd(colKey, key) {
      let newPasswordMaps =  extend(true, {}, this.passwordMaps);

      let newPasswordMap = newPasswordMaps[key];
      newPasswordMap[colKey].isPwd = !newPasswordMap[colKey].isPwd;

      this.passwordMaps = newPasswordMaps;
    },

    getPlaceHolderByKey: function(key, cols) {
      const find = cols.find(t => t.name === key);
      if (find) {
        return find.placeHolder;
      }
      return null;
    },

    addRow() {
      console.log("CTableList-> addRow");
      const index = this.qTableData.length + 1;
      const newRow = {
        id: (new Date()).valueOf()
      };

      this.insertColumns.forEach((column) => {
        newRow[column.name] = column.value;
      });
     
      this.qTableData  = [ ...this.qTableData.slice(0, index), newRow, ...this.qTableData.slice(index) ];

      const id = this.getRecIdByDataMap(newRow);

      this.passwordMaps[id] = extend(true, {}, this.passwordMap);
    },

    removeRow(id) {
      const index = this.qTableData.findIndex(t => this.getRecId(t) === id);
      console.log(index);
      if (index >= 0) {
        this.qTableData = [ ...this.qTableData.slice(0, index), ...this.qTableData.slice(index + 1) ];
      }

      delete this.passwordMaps[id];
    },

    batchRemoveRow(ids) {
      ids.forEach((id) => {
        this.removeRow(id);
      });
    },

    onNewClickAction() {
      this.addRow();
    },

    async onDeleteClickAction(row) {
      let ids = [];
      this.selected.forEach((item) => {
        ids.push(this.getRecId(item));
      });
      console.info(JSON.stringify(ids));
      if (row) {
        this.removeRow(this.getRecId(row));
      } else {
        this.batchRemoveRow(ids);
        this.selected = [];
      }
    },

    getData() {
      let newData = [];
      let index = 0;
      let that = this;
      const colums = this.qTableColums;
      this.qTableData.forEach((t) => {
          let newDataItem = {};
          for (let columnName in t) {
            const value = t[columnName];
            const relation = this.relationMap[columnName];
            if (value && relation) {
              const col = colums.find(t => t.name === columnName);
              if (col.multipleValue) {
                let valueArr = [];
                value.forEach((v) => {
                  valueArr.push(v[relation.toColumn.name]);
                });

                newDataItem[columnName] = valueArr.join(",");
              } else {
                newDataItem[columnName] = value && value[relation.toColumn.name];
              }

              newDataItem[relation.name] = value;
            } else {
              if (value != undefined
                && value != null
                && value.toString().trim() !== "") {
                newDataItem[columnName] = value;
              }
            }
          }

          that.oneToOneMainToSubTables.forEach((oneToOneMainToSubTable) => {
            const refName = 'rTableNewRef' + oneToOneMainToSubTable.relationName + this.getRecId(newDataItem);
            console.dir(refName);
            const ref = that.$refs[refName];
            console.dir(ref);
            const subData = ref[0].getData();
            newDataItem[oneToOneMainToSubTable.relationName] = subData;
          });

          that.oneToManySubTables.forEach((oneToManySubTable) => {
            const refName = 'rTableListRef' + oneToManySubTable.relationName + this.getRecId(newDataItem);
            console.dir(refName);
            const ref = that.$refs[refName];
            console.dir(ref);
            const subData = ref[0].getData();
            newDataItem[oneToManySubTable.relationName] = subData;
          });

          delete newDataItem.createdDate;
          delete newDataItem.lastModifiedDate;
          newData.push(newDataItem);
      });
      console.dir(newData);
      return newData;
    },

    hideRefPopProxyAction(ref) {
      const proxys = this.$refs[ref];
      for (let i = 0; i < proxys.length; i++) {
        proxys[i].hide();
      }
    },


    getInputTextType: function(props, colKey) {
      if (this.passwordMaps[props.key] && this.passwordMaps[props.key][colKey].isPwd) {
        return "password";
      } else {
        return "text";
      }
    },

    isPasswordTextType: function(props, colKey) {
      if (this.passwordMaps[props.key] && this.passwordMaps[props.key][colKey].isPwd) {
        return true;
      } else {
        return false;
      }
    },

    getInputIcon: function(props, colKey) {
      if (this.passwordMaps[props.key] && this.passwordMaps[props.key][colKey].isPwd) {
        return "visibility_off";
      } else {
        return "visibility";
      }
    },

    getRefName: function(prefix, relationName, row) {
      const refName = prefix + relationName + this.getRecId(row);
      console.log(refName);
      return refName;
    },

    getRecId(row) {
      if (this.primaryNames.length === 1) {
        return row[this.primaryNames[0]];
      } else {
        let recIds = [];
        this.primaryNames.forEach((primaryName) => {
          recIds.push(primaryName + "=" + row[primaryName]);
        });

        const recId = recIds.join(",");
        console.log(recId);

        return recId;
      }
    },

    getRecIdByDataMap(dataMap) {
      const primaryNames = this.primaryNames;
      if (primaryNames.length === 1) {
        return dataMap[primaryNames[0]];
      } else {
        let recIds = [];
        primaryNames.forEach((primaryName) => {
          recIds.push(primaryName + "=" + dataMap[primaryName]);
        });

        const recId = recIds.join(",");
        console.log(recId);

        return recId;
      }
    },

    openDialogClickAction(props, colKey) {
      const col = props.cols.find(t => t.name === colKey);
      const row = props.row;
      this.$q.dialog({
        component: CTableListReadDialog,

        // optional if you want to have access to
        // Router, Vuex store, and so on, in your
        // custom component:
        parent: this, // becomes child of this Vue node
                      // ("this" points to your Vue component)
                      // (prop was called "root" in < 1.1.0 and
                      // still works, but recommending to switch
                      // to data: the more appropriate "parent" name)

        // props forwarded to component
        // (everything except "component" and "parent" props above):
        tableName: col.relationTableName,
        selectionProp: col.multipleValue ? 'multiple': 'single',
        data: row[colKey],
        dataSource: this.dataSource
      }).onOk((data) => {
        row[colKey] = data;
      }).onCancel(() => {
        console.log('Cancel')
      }).onDismiss(() => {
        console.log('Called on OK or Cancel')
      });
    },


    async loadMeta() {
      const that = this;
      this.loading = true;
      try {
        /* 主表元数据 */
        const table = await metadataTableService.getByName(this.dataSource, this.tableName);
        this.tableCaption = table.caption;
        this.primaryNames = table.primaryNames;

        /* 关联关系 */
        const tableRelations = await metadataRelationService.getByName(this.dataSource, this.tableName);

        /* 关联表元数据 */
        let relationMetadataMap = {};
        await Promise.all(tableRelations.map(async (tableRelation) => {
          const relationTable = await metadataTableService.getByName(this.dataSource, tableRelation.toTable.name);
          relationMetadataMap[tableRelation.toTable.name] = relationTable;
        }));
        this.relationMetadataMap = relationMetadataMap;

        let relationMap = {};
        let oneToOneMainToSubTables = [];
        let oneToManySubTables = [];
        tableRelations.forEach((tableRelation) => {
          if (tableRelation.relationType === "OneToOneMainToSub") {
            oneToOneMainToSubTables.push({
              "relationName": tableRelation.name,
              "tableName": tableRelation.toTable.name,
              "fkColumnName": tableRelation.toColumn.name
            });
          } else if (tableRelation.relationType === "OneToMany") {
            oneToManySubTables.push({
              "relationName": tableRelation.name,
              "tableName": tableRelation.toTable.name,
              "fkColumnName": tableRelation.toColumn.name
            });
          } else if (tableRelation.relationType === "ManyToOne"
            || tableRelation.relationType === "OneToOneSubToMain") {
             const fromColumnName = tableRelation.fromColumn.name;
             relationMap[fromColumnName] = tableRelation;
          }
        });
        this.oneToOneMainToSubTables = oneToOneMainToSubTables;
        this.oneToManySubTables = oneToManySubTables;
        this.relationMap = relationMap;

        let insertColumns = [];
        for (let i = 0; i < table.columns.length; i++) {
          const column = table.columns[i];

          if (column.insertable) {
            const columnName = column.name;
            if (this.fkColumnName && columnName === this.fkColumnName) {
              continue;
            }

            if (column.defaultValue === "true") {
              column.value = true;
            } else if (column.defaultValue === "false") {
              column.value = false;
            } else {
              column.value = column.defaultValue;
            }

            if (column.dataType === 'PASSWORD') {
              column.isText = false;
              column.isPwd = true;
            } else {
              column.isText = true;
              column.isPwd = false;
            }

            const relation = this.relationMap[columnName];
            if (relation) {
              column.relationTableName = relation.toTable.name;
              column.relationColumnName = relation.toColumn.name;
              column.relationDisplayColumns = that.getDisplayableColumns(relationMetadataMap[column.relationTableName]);
              insertColumns.push(column);
            } else {
              insertColumns.push(column);
            }
          }
        }

        this.insertColumns = insertColumns;
        let qTableColums = [];
        qTableColums.push({
          name: "dataClickAction",
          align: "center",
          label: "操作",
          field: "dataClickAction",
          sortable: true
        });

        insertColumns.forEach((column) => {
          this.passwordMap[column.name] = {
            isPwd: column.isPwd,
            isText: column.isText
          };

          qTableColums.push({
            name: column.name,
            align: "left",
            label: column.caption,
            field: column.name,
            dataType: column.dataType,
            sortable: false,
            placeHolder: column.description,
            relationTableName: column.relationTableName,
            relationColumnName: column.relationColumnName,
            relationDisplayColumns: column.relationDisplayColumns,
            multipleValue: column.multipleValue,
            isPwd: column.isPwd,
            isText: column.isText
          });
        });

        this.qTableColums = qTableColums;

        this.loading = false;
      } catch (error) {
        this.loading = false;
        console.error(error);
      }
    },

    getDisplayableColumns(tableMetadata) {
      const displayableColumns = tableMetadata.columns.filter(t => t.displayable === true);
      return displayableColumns;
    }
  }
};
</script>
